/**
 * ReportGear(2011)
 */
package net.abbp.report.view.cell.editor;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.Collections;
import java.util.List;

import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.SwingUtilities;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;

import net.abbp.report.context.ReportContext;
import net.abbp.report.model.ReportModel;
import net.abbp.report.view.GridView;
import net.abbp.report.view.cell.value.FormulaValue;
import net.abbp.swing.layout.LayoutUtils;

import com.reportgear.core.swing.pane.base.EditorPane;
import com.reportgear.report.model.script.function.Function;
import com.reportgear.report.model.script.function.FunctionManager;
import com.reportgear.report.model.script.function.Function.Type;
import com.reportgear.report.model.script.var.VarInfo;
import com.reportgear.report.model.script.var.VarManager;

/**
 * 公式编辑面板
 * 
 * @version 1.0 2011-5-2
 * @author <a herf="lexloo@gmail.com">lexloo</a>
 * @since Report 1.0
 */
public class FormulaPane extends EditorPane<FormulaValue> {
    private static final long serialVersionUID = -9125002127911251495L;
    private FormulaInputPane formulaInputPane;
    private SelectInfoPane selectInfoPane;
    private DescInfoPane descInfoPane;
    private FormulaValue formula;

    public FormulaPane() {
        this.initComponents();
    }

    private void initComponents() {
        this.setLayout(new BorderLayout());

        this.formulaInputPane = new FormulaInputPane();
        this.add(this.formulaInputPane, BorderLayout.NORTH);

        this.selectInfoPane = new SelectInfoPane();
        this.add(this.selectInfoPane, BorderLayout.CENTER);

        this.descInfoPane = new DescInfoPane();
        this.add(this.descInfoPane, BorderLayout.EAST);
    }

    // 插入文本
    private void insertText(String text) {
        this.formulaInputPane.applyText(text);
    }

    // 显示描述
    private void displayDescription(String description) {
        this.descInfoPane.showDescription(description);
    }

    // 清空描述
    protected void clearDescription() {
        this.descInfoPane.showDescription("");
    }

    // 公式输入面板
    @SuppressWarnings("serial")
    private class FormulaInputPane extends JPanel {
        private JTextArea formulaTextArea;

        private FormulaInputPane() {
            this.setLayout(new BorderLayout());

            this.add(new JLabel("公式编辑"), BorderLayout.NORTH);
            this.formulaTextArea = new JTextArea(5, 0);
            this.formulaTextArea.setLineWrap(true);
            this.add(new JScrollPane(this.formulaTextArea), BorderLayout.CENTER);

            JPanel paneBtns = new JPanel();
            paneBtns.setLayout(new GridBagLayout());
            paneBtns.setBorder(BorderFactory.createTitledBorder("输入键"));

            paneBtns.add(new OperateButton("+"), LayoutUtils.newGridBagConstraints(0, 0, 1, 1));
            paneBtns.add(new OperateButton("-"), LayoutUtils.newGridBagConstraints(1, 0, 1, 1));
            paneBtns.add(new OperateButton("*"), LayoutUtils.newGridBagConstraints(2, 0, 1, 1));
            paneBtns.add(new OperateButton("/"), LayoutUtils.newGridBagConstraints(3, 0, 1, 1));
            // paneBtns.add(new OperateButton(","),
            // LayoutHelper.newGridBagConstraints(4, 0, 1, 1));

            ActionListener comboBoxListener = new ActionListener() {

                @Override
                public void actionPerformed(ActionEvent evt) {
                    JComboBox comboBox = (JComboBox) evt.getSource();
                    FormulaPane.this.insertText(String.valueOf(comboBox.getSelectedItem()));
                }
            };

            JComboBox columnComboBox = new JComboBox(new Character[] { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I',
                    'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z' });
            JComboBox rowComboBox = new JComboBox(new Character[] { '1', '2', '3', '4', '5', '6', '7', '8', '9', '0' });
            columnComboBox.addActionListener(comboBoxListener);
            rowComboBox.addActionListener(comboBoxListener);

            paneBtns.add(columnComboBox, LayoutUtils.newGridBagConstraints(0, 1, 2, 1));
            paneBtns.add(rowComboBox, LayoutUtils.newGridBagConstraints(2, 1, 2, 1));
            this.add(paneBtns, BorderLayout.EAST);
        }

        private void applyText(String text) {
            if ((text == null) || (text.length() <= 0)) {
                return;
            }

            this.formulaTextArea.insert(text, this.formulaTextArea.getCaretPosition());
            this.formulaTextArea.getText();
            if (text.indexOf("()") != -1) {
                this.formulaTextArea.setCaretPosition(this.formulaTextArea.getCaretPosition() - 1);
            }

            this.formulaTextArea.requestFocus();
        }

        private String getText() {
            return this.formulaTextArea.getText().trim();
        }
    }

    // 选择信息面板
    @SuppressWarnings("serial")
    private class SelectInfoPane extends JPanel {
        private CatalogPane catalogPane;
        private ObjectSelectPane objSelectPane;

        private SelectInfoPane() {
            this.setLayout(new BorderLayout());
            this.objSelectPane = new ObjectSelectPane();

            this.catalogPane = new CatalogPane(this.objSelectPane);
            this.add(this.catalogPane, BorderLayout.WEST);

            this.add(this.objSelectPane, BorderLayout.CENTER);
        }
    }

    // 分类面板
    @SuppressWarnings("serial")
    private class CatalogPane extends JPanel {
        private FunctionPane fnPane;
        private VarAndParamPane vapPane;

        private CatalogPane(ObjectSelectPane selectPane) {
            this.setLayout(new BorderLayout());

            this.fnPane = new FunctionPane();
            this.add(this.fnPane, BorderLayout.CENTER);
            this.fnPane.setSelectPane(selectPane);

            this.vapPane = new VarAndParamPane();
            this.add(this.vapPane, BorderLayout.SOUTH);
            this.vapPane.setSelectPane(selectPane);
        }
    }

    // 函数选择面板
    @SuppressWarnings("serial")
    private class FunctionPane extends JPanel {
        private JList fnCatalog;
        private ObjectSelectPane selectPane;

        private FunctionPane() {
            this.setLayout(new BorderLayout());
            this.setPreferredSize(new Dimension(180, 32));

            this.initCatalog();

            this.add(new JLabel("函数"), BorderLayout.NORTH);
            this.add(new JScrollPane(this.fnCatalog), BorderLayout.CENTER);
        }

        // 初始化函数分类
        private void initCatalog() {
            this.fnCatalog = new JList(Function.Type.values());
            this.fnCatalog.addListSelectionListener(new ListSelectionListener() {

                @Override
                public void valueChanged(ListSelectionEvent evt) {
                    if (evt.getValueIsAdjusting()) {
                        return;
                    }

                    JList list = (JList) evt.getSource();

                    Function.Type type = (Type) list.getSelectedValue();

                    selectPane.updateByFunctionType(type);

                    FormulaPane.this.clearDescription();
                }
            });
        }

        private void setSelectPane(ObjectSelectPane selectPane) {
            this.selectPane = selectPane;
        }
    }

    // 参数选择面板
    @SuppressWarnings("serial")
    private class VarAndParamPane extends JPanel {
        private JList varList;
        private ObjectSelectPane selectPane;

        private VarAndParamPane() {
            this.setLayout(new BorderLayout());

            this.add(new JLabel("变量与参数"), BorderLayout.NORTH);
            varList = new JList(new String[] { "变量", "报表参数" });
            varList.setBorder(BorderFactory.createLineBorder(Color.GRAY));
            this.add(varList, BorderLayout.CENTER);

            varList.addListSelectionListener(new ListSelectionListener() {

                @Override
                public void valueChanged(ListSelectionEvent evt) {
                    if (evt.getValueIsAdjusting()) {
                        return;
                    }

                    JList list = (JList) evt.getSource();

                    if (list.getSelectedIndex() == 0) {
                        selectPane.updateByVars();
                    } else if (list.getSelectedIndex() == 1) {
                        selectPane.updateByParameters();
                    }

                    FormulaPane.this.clearDescription();
                }
            });
        }

        private void setSelectPane(ObjectSelectPane selectPane) {
            this.selectPane = selectPane;
        }
    }

    // 对象选择面板
    @SuppressWarnings("serial")
    private class ObjectSelectPane extends JPanel {
        private JList itemsList;

        private ObjectSelectPane() {
            this.setLayout(new BorderLayout());
            this.setBorder(BorderFactory.createEmptyBorder(0, 10, 0, 10));

            this.itemsList = new JList();
            this.add(new JLabel("选择"), BorderLayout.NORTH);
            this.add(new JScrollPane(this.itemsList), BorderLayout.CENTER);
            this.itemsList.addMouseListener(new MouseAdapter() {

                @Override
                public void mouseClicked(MouseEvent evt) {
                    if (evt.getClickCount() == 2) {
                        JList list = (JList) evt.getSource();

                        Object value = list.getSelectedValue();
                        if (value instanceof Function) {
                            FormulaPane.this.insertText(value.toString() + "()");
                        } else if (value instanceof VarInfo) {
                            FormulaPane.this.insertText(value.toString());
                        }
                    }
                }
            });

            this.itemsList.addListSelectionListener(new ListSelectionListener() {

                @Override
                public void valueChanged(ListSelectionEvent evt) {
                    JList list = (JList) evt.getSource();

                    Object value = list.getSelectedValue();
                    if (value instanceof Function) {
                        FormulaPane.this.displayDescription(((Function) value).getDescription());
                    } else if (value instanceof VarInfo) {

                        FormulaPane.this.displayDescription(((VarInfo) value).desc);
                    }
                }
            });
        }

        /**
         * 更新参数
         */
        public void updateByParameters() {
            GridView worksheet = ReportContext.INSTANCE.getCurrentView();
            if (worksheet == null) {
                this.itemsList.setListData(new Object[0]);
            } else {
                ReportModel model = worksheet.getReportModel();
                this.itemsList.setListData(model.getParameters().toArray());
            }
        }

        /**
         * 更新变量
         */
        public void updateByVars() {
            this.itemsList.setListData(VarManager.INSTANCE.getAllVars());
        }

        /**
         * 通过函数类型更新
         * 
         * @param type
         *            函数类型
         */
        private void updateByFunctionType(Function.Type type) {
            List<Function> fnList = FunctionManager.INSTANCE.getTypeList(type);

            Collections.sort(fnList);

            this.itemsList.setListData(fnList.toArray());
        }
    }

    // 描述信息显示面板
    @SuppressWarnings("serial")
    private static class DescInfoPane extends JPanel {
        private JTextArea descInfoArea;

        private DescInfoPane() {
            this.setLayout(new BorderLayout());
            this.setPreferredSize(new Dimension(200, 32));
            this.add(new JLabel("说明"), BorderLayout.NORTH);

            this.descInfoArea = new JTextArea();
            this.descInfoArea.setEditable(false);
            this.add(new JScrollPane(this.descInfoArea), BorderLayout.CENTER);
        }

        private void showDescription(String description) {
            this.descInfoArea.setText(description);
        }
    }

    /**
     * 操作按钮
     */
    @SuppressWarnings("serial")
    private class OperateButton extends JButton implements ActionListener {
        public OperateButton(String text) {
            super(text);
            addActionListener(this);
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(42, 32);
        }

        public void actionPerformed(ActionEvent evt) {
            FormulaPane.this.insertText(this.getText());
        }
    }

    @Override
    public void populate(FormulaValue formula) {
        this.formula = formula;
        String value = formula.getFormula();

        if (value == null) {
            return;
        } else {
            this.formulaInputPane.applyText(value);
        }
    }

    @Override
    public FormulaValue update() {
        this.formula.setFormula(this.formulaInputPane.getText());

        return this.formula;
    }

    @Override
    public int showDialog(Component owner) {
        return this.showDialog(SwingUtilities.getWindowAncestor(owner), "公式编辑", 600, 400);
    }
}
